/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package stud.cp.user.dbaccess;

import java.math.BigInteger;
import java.sql.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.LinkedList;
import java.util.List;
import org.apache.log4j.Logger;
import stud.cp.core.dbaccess.DAO;
import stud.cp.core.dbaccess.DAOException;
import stud.cp.user.valueobjects.History;

/**
 * Класс, предоставляющий доступ к таблице history.
 *
 * @author Morfant
 */
public class HistoryDAO implements DAO<History> {

    /**
     * Логгер.
     */
    private static Logger logger = Logger.getLogger("CPTNP");
    /**
     * Список названий колонок таблицы history..
     */
    private static String[] historyColumnName = {"history_id",
        "object_id",
        "property_id",
        "user_id",
        "change_date",
        "new_value",
        "old_value"};
    /**
     * Список названий колонок таблицы properties..
     */
    private static String[] propetyColumnName = {"property_id",
        "property_type_id",
        "property_group_id",
        "property_name",//[4]
        "property_type_def_id"};
    /**
     * Имя колонок таблицы object
     */
    private static String[] objectColumnName = {"object_id", "object_name", "description", "object_type_id"};//[1]
    /**
     * Список названий колонок таблицы users..
     */
    private static String[] usersColumnName = {"user_id",
        "user_type_id",
        "user_name",//[2]
        "password"};
    /**
     * Коннект к базе данных.
     */
    private Connection connection = null;

    /**
     * Конструктор, который устанавливает коннект к базе данных.
     *
     * @param connection Связь с базой данных.
     */
    public HistoryDAO(Connection connection) {
        this.connection = connection;
    }

    @Override
    public History getById(BigInteger id) throws DAOException {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void update(History entry) throws DAOException {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    /**
     * Запрос на добавление данных.
     *
     * @param history_id ID записи истории
     * @param object_id ID оружия
     * @param property_id ID свойства.
     * @param user_id ID пользователя.
     * @param change_date дата изменения
     * @param new_value новые данные
     * @param old_value старые данные
     * @return запрос
     */
    private String getQueryForInsert(BigInteger history_id,
            BigInteger object_id, BigInteger property_id, BigInteger user_id, String change_date,
            String new_value, String old_value) {
        StringBuilder query = new StringBuilder();
        query.append("insert into history(history_id,object_id,property_id,user_id,change_date,new_value,old_value) \n");
        query.append("values(");
        query.append(history_id);
        query.append(",");
        query.append(object_id);
        query.append(",");
        query.append(property_id);
        query.append(",");
        query.append(user_id);
        query.append(",'");
        query.append(change_date);
        query.append("','");
        query.append(new_value);
        query.append("','");
        query.append(old_value);
        query.append("')");
        return query.toString();
    }

    /**
     * Зарпос на получения следующего ID.
     *
     * @return Зарпос.
     */
    private String getQueryForSelectNextID() {
        StringBuilder query = new StringBuilder();
        query.append("SELECT history_seq.NEXTVAL from dual \n");
        return query.toString();
    }

    /**
     * Зарпос на получения максимального id из таблицы.
     *
     * @return Зарпос.
     */
    private String getQueryForSelectMaxId() {
        StringBuilder query = new StringBuilder();
        query.append("SELECT MAX(history_id) \n");
        query.append("FROM history");
        return query.toString();
    }

    /**
     * Создание новой записи..
     *
     * @param entry Запись.
     * @throws DAOException <p> Ошибка сохранения данных. </p>
     */
    @Override
    public BigInteger create(History entry) throws DAOException {
        ResultSet set = null;
        PreparedStatement prestat = null;
        CallableStatement proc;
        try {
            proc = connection.prepareCall("{ call GetNextIdentity(?,?)}");
            proc.setString(1, "history");
            proc.registerOutParameter(2, java.sql.Types.BIGINT);

            proc.execute();

            BigInteger index = proc.getBigDecimal(2).toBigInteger();

            proc.close();
            DateFormat formatter = new SimpleDateFormat("dd-MMM-yyyy");
            prestat = connection.prepareStatement(
                    getQueryForInsert(index,
                    entry.getObjectID(),
                    entry.getPropertyID(),
                    entry.getUserID(),
                    formatter.format(entry.getDate()),
                    entry.getNewValue(),
                    entry.getOldValue()));
            prestat.executeUpdate();
            return index;
        } catch (SQLException ex) {
            logger.debug("DAO_propeties", ex);
            throw new DAOException("Ошибка при создание данных..", ex);
        } finally {
            if (prestat != null) {
                try {
                    prestat.close();
                } catch (SQLException ex) {
                    logger.debug("DAO_propety", ex);
                    throw new DAOException("Ошибка закрытия ResultSet`а.", ex);
                }
            }
        }
    }

    /**
     * Запрос, позволяющий при выполнении получить полностью данные из таблицы
     *
     * @return Строка запроса.
     */
    private String getQueryForAllHistory() {
        StringBuilder query = new StringBuilder();
        query.append("select h.history_id,h.object_id,h.property_id,h.user_id,h.change_date,h.new_value,h.old_value,");
        query.append("w.name as \"object_name\",p.name as \"property_name\",u.name as \"user_name\" \n");
        query.append("from history h \n");
        query.append("inner join objects w on w.object_id=h.object_id \n");
        query.append("inner join properties p on p.property_id=h.property_id \n");
        query.append("inner join users u on u.user_id=h.user_id \n");
        return query.toString();
    }

    /**
     * Метод, который возвращает список значений из таблицы
     *
     * @return Список данных.
     */
    @Override
    public List<History> getAll() throws DAOException {
        List<History> data_list = new LinkedList<History>();
        ResultSet set = null;
        PreparedStatement prestat = null;
        try {
            prestat = connection.prepareStatement(getQueryForAllHistory());
            set = prestat.executeQuery();
            while (set.next()) {
                data_list.add(new History(set.getBigDecimal(historyColumnName[0]).toBigInteger(),
                        set.getBigDecimal(historyColumnName[1]).toBigInteger(),
                        set.getBigDecimal(historyColumnName[2]).toBigInteger(),
                        set.getBigDecimal(historyColumnName[3]).toBigInteger(),
                        set.getDate(historyColumnName[4]),
                        set.getString(historyColumnName[5]),
                        set.getString(historyColumnName[6]),
                        set.getString(propetyColumnName[4]),
                        set.getString(usersColumnName[2]),
                        set.getString(objectColumnName[1])));
            }
        } catch (SQLException ex) {
            logger.debug("DAO_propeties", ex);
            throw new DAOException("Ошибка получения списка данных.", ex);
        } finally {
            if (prestat != null) {
                try {
                    prestat.close();
                } catch (SQLException ex) {
                    logger.debug("DAO_propety", ex);
                    throw new DAOException("Ошибка закрытия ResultSet`а.", ex);
                }
            }
        }
        return data_list;
    }

    /**
     * Запрос, позволяющий при выполнении получить полностью историю для
     * конкретного оружия.
     *
     * @return Строка запроса.
     */
    private String getQueryForAllHistoryForObject(BigInteger object_id) {
        StringBuilder query = new StringBuilder();
        query.append("select h.history_id,h.object_id,h.property_id,h.user_id,h.change_date,h.new_value,h.old_value,");
        query.append("w.name as \"object_name\",p.name as \"property_name\",u.name as \"user_name\" \n");
        query.append("from history h \n");
        query.append("inner join objects w on w.object_id=h.object_id \n");
        query.append("inner join properties p on p.property_id=h.property_id \n");
        query.append("inner join users u on u.user_id=h.user_id \n");
        query.append("where w.object_id=");
        query.append(object_id);
        query.append("\n order by h.history_id");
        return query.toString();
    }

    /**
     * Метод, который возвращает список историю для конкретного оружия.
     *
     * @return Список данных.
     */
    public List<History> getAllForObject(BigInteger object_id) throws DAOException {
        List<History> data_list = new LinkedList<History>();
        ResultSet set = null;
        PreparedStatement prestat = null;
        try {
            prestat = connection.prepareStatement(getQueryForAllHistoryForObject(object_id));
            set = prestat.executeQuery();
            while (set.next()) {
                data_list.add(new History(set.getBigDecimal(historyColumnName[0]).toBigInteger(),
                        set.getBigDecimal(historyColumnName[1]).toBigInteger(),
                        set.getBigDecimal(historyColumnName[2]).toBigInteger(),
                        set.getBigDecimal(historyColumnName[3]).toBigInteger(),
                        set.getDate(historyColumnName[4]),
                        set.getString(historyColumnName[5]),
                        set.getString(historyColumnName[6]),
                        set.getString(propetyColumnName[3]),
                        set.getString(usersColumnName[2]),
                        set.getString(objectColumnName[1])));
            }
        } catch (SQLException ex) {
            logger.debug("DAO_propeties", ex);
            throw new DAOException("Ошибка получения списка данных.", ex);
        } finally {
            if (prestat != null) {
                try {
                    prestat.close();
                } catch (SQLException ex) {
                    logger.debug("DAO_propety", ex);
                    throw new DAOException("Ошибка закрытия ResultSet`а.", ex);
                }
            }
        }
        return data_list;
    }

    /**
     * Зарпос на удаление из таблицы записи по id.
     *
     * @param id ID
     * @return Зарпос.
     */
    private String getQueryForDelete(BigInteger id) {
        StringBuilder query = new StringBuilder();
        query.append("DELETE FROM history \n");
        query.append("WHERE history_id=");
        query.append(id);
        return query.toString();
    }

    /**
     * Метод, позволяющий удалять данные по записи.
     *
     * @param id Запись.
     * @throws DAOException
     */
    @Override
    public void delete(BigInteger id) throws DAOException {
        PreparedStatement prestat = null;
        try {
            prestat = connection.prepareStatement(getQueryForDelete(id));
            prestat.executeUpdate();
        } catch (SQLException ex) {
            logger.debug("DAO_propeties", ex);
            throw new DAOException("Ошибка удаления данных.", ex);
        } finally {
            if (prestat != null) {
                try {
                    prestat.close();
                } catch (SQLException ex) {
                    logger.debug("DAO_propety", ex);
                    throw new DAOException("Ошибка закрытия ResultSet`а.", ex);
                }
            }
        }
    }
}
